package cn.monkey.chat.server.connect.config;

import cn.monkey.io.transport.netty.ChannelInitCustomizer;
import cn.monkey.io.transport.netty.server.ServerTransport;
import cn.monkey.io.transport.netty.server.codec.protocol.ServerProtocolRouterFunction;
import cn.monkey.io.transport.netty.server.codec.protocol.SimpleMultipartServerProtocolSelector;
import io.netty.channel.Channel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.sctp.nio.NioSctpServerChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

@Configuration
public class ServerTransportConfig {

    @Bean
    ChannelInitCustomizer channelInitCustomizer(List<ServerProtocolRouterFunction> serverProtocolRouterFunctions) {
        serverProtocolRouterFunctions.sort(AnnotationAwareOrderComparator.INSTANCE);
        return serverChannel -> {
            SimpleMultipartServerProtocolSelector simpleMultipartServerProtocolSelector = new SimpleMultipartServerProtocolSelector();
            serverProtocolRouterFunctions.forEach(simpleMultipartServerProtocolSelector::add);
            serverChannel.pipeline().addLast(simpleMultipartServerProtocolSelector);
        };
    }

    @Bean
    @ConfigurationProperties(prefix = "server.port")
    ServerPortProperties serverPortProperties() {
        return new ServerPortProperties();
    }

    @Bean
    ServerTransport serverTransport(List<ChannelInitCustomizer> channelInitCustomizers,
                                    ServerPortProperties serverPortProperties) {
        List<Consumer<Channel>> channelInitCustomizerList = new ArrayList<>(channelInitCustomizers);

        Consumer<Channel> channelInitCustomizer = channelInitCustomizerList.stream()
                .reduce(Consumer::andThen)
                .orElseThrow(() -> new IllegalArgumentException("no channelInitCustomizer"));

        return new ServerTransport(new cn.monkey.io.transport.netty.server.ServerTransportConfig()
                .mutate()
                .channelClass(NioServerSocketChannel.class)
                .eventLoopGroup(new NioEventLoopGroup(1))
                .childGroup(new NioEventLoopGroup(2))
                .socketAddress(() -> new InetSocketAddress(serverPortProperties.getPort()))
                .doOnChannelInit(channelInitCustomizer).build());
    }
}
